﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using MathematicallySafe.HeadCounter.Data.Interfaces;
using StructureMap;

namespace MathematicallySafe.HeadCounter.Data.Models
{
    public enum LootOutcome
    {
        Won,
        Offspec,
        Banked,
        Disenchanted,
    }

    public class RaidLoot
    {
        private static IGuild _guild;
        private static IGuild Guild
        {
            get
            {
                if (_guild == null)
                {
                    _guild = ObjectFactory.GetInstance<IGuild>();
                }

                return _guild;
            }
        }
        
        private static ILootTable _lootTable;
        private static ILootTable LootTable
        {
            get
            {
                if (_lootTable == null)
                {
                    _lootTable = ObjectFactory.GetInstance<ILootTable>();
                }

                return _lootTable;
            }
        }

        private LootItem _item;
        private LootOutcome _outcome;
        private string _winner;
        private string _winnerIdentity;

        [XmlAttribute]
        public int ID { get; set; }

        [XmlAttribute]
        public DateTime Time { get; set; }

        [XmlAttribute]
        public string Winner
        {
            get { return _winner; }
            set
            {
                // todo this is all sorts of wrong.  Need to separate assignments from desirialisation
                // and from re-assignments when we need to raise events etc.

                if (_winner != value)
                {
                    _winner = value;
                    _winnerIdentity = null;
                }

//                if (_winner != value)
//                {
//                    string originalWinner = _winner;
//                    _winner = value;
//
//                    if (Outcome == LootOutcome.Won)
//                    {
//                        var raider = Guild.FindRaider(_winner);
//                        if (raider != null)
//                        {
//                            if (_item != null) raider.AddGear(_item.ID, true);
//                            WinnerIdentity = raider.Identity;
//                        }
//                    }
//                    else
//                    {
//                        WinnerIdentity = "";
//                    }
//
//                    if (originalWinner != null)
//                    {
//                        var originalRaider = Guild.FindRaider(originalWinner);
//                        if (originalRaider != null) originalRaider.RemoveGear(_item.ID);
//                    }
//
//                    OnWinnerChanged(new WinnerChangedEventArgs(originalWinner, _winner));
//                }
            }
        }

        public void SetWinner(string winner)
        {
            if (_winner != winner)
            {
                string originalWinner = _winner;
                _winner = winner;

                if (Outcome == LootOutcome.Won)
                {
                    var raider = Guild.FindRaider(_winner);
                    if (raider != null)
                    {
                        if (_item != null) raider.AddGear(_item.ID, true);
                        WinnerIdentity = raider.Identity;
                    }
                }
                else
                {
                    WinnerIdentity = "";
                }

                if (originalWinner != null)
                {
                    var originalRaider = Guild.FindRaider(originalWinner);
                    if (originalRaider != null) originalRaider.RemoveGear(_item.ID);
                }

                OnWinnerChanged(new WinnerChangedEventArgs(originalWinner, _winner));
            }
        }

        public void SetNoWinner()
        {
            // todo remind me why we need winner and winner identity?
            Winner = "";
            WinnerIdentity = "";
        }

        [XmlAttribute]
        public string WinnerIdentity
        {
            get
            {
                if (string.IsNullOrEmpty(_winnerIdentity))
                {
                    if (!string.IsNullOrEmpty(_winner))
                    {
                        var raider = Guild.FindRaider(_winner);
                        if (raider != null)
                        {
                            WinnerIdentity = raider.Identity;
                        }

                    }
                }

                return _winnerIdentity;
            }

            set { _winnerIdentity = value; }
        }

        [XmlAttribute]
        public string ItemName { get; set; }

        [XmlAttribute]
        public string Boss { get; set; }

        [XmlElement]
        public LootOutcome Outcome
        {
            get { return _outcome; }
            set
            {
                if (_outcome != value)
                {
                    var originalOutcome = _outcome;
                    _outcome = value;

                    OnOutcomeChanged(new OutcomeChangedEventArgs(originalOutcome, _outcome));

                    if (_outcome != LootOutcome.Won)
                    {
                        SetNoWinner();
                    }
                }
            }
        }

        [XmlIgnore]
        public LootItem Item
        {
            get
            {
                if (_item == null)
                {
                    _item = LootTable[ID];
                }

                return _item;
            }
        }

        public event EventHandler<WinnerChangedEventArgs> WinnerChanged;

        protected virtual void OnWinnerChanged(WinnerChangedEventArgs e)
        {
            if (WinnerChanged != null)
            {
                WinnerChanged(this, e);
            }
        }

        public event EventHandler<OutcomeChangedEventArgs> OutcomeChanged;

        protected virtual void OnOutcomeChanged(OutcomeChangedEventArgs e)
        {
            if (OutcomeChanged != null)
            {
                OutcomeChanged(this, e);
            }
        }
    }

    public class WinnerChangedEventArgs : EventArgs
    {
        public readonly string OriginalWinner;
        public readonly string NewWinner;

        public WinnerChangedEventArgs(string originalWinner, string newWinner)
        {
            OriginalWinner = originalWinner;
            NewWinner = newWinner;
        }
    }

    public class OutcomeChangedEventArgs : EventArgs
    {
        public readonly LootOutcome OriginalOutcome;
        public readonly LootOutcome ChangedOutcome;

        public OutcomeChangedEventArgs(LootOutcome originalOutcome, LootOutcome changedOutcome)
        {
            OriginalOutcome = originalOutcome;
            ChangedOutcome = changedOutcome;
        }
    }
}